/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package controllers.learningmodel;

import tools.*;
import core.game.Observation;
import core.game.StateObservation;

import java.awt.desktop.SystemSleepEvent;
import java.io.FileWriter;
import java.util.*;

import ontology.Types;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;

/**
 *
 * @author yuy
 */
public class RLDataExtractor {
    public FileWriter filewriter;
    public static Instances s_datasetHeader = datasetHeader();
    
    public RLDataExtractor(String filename) throws Exception{
        
        filewriter = new FileWriter(filename+".arff");
        filewriter.write(s_datasetHeader.toString());
        /*
                // ARFF File header
        filewriter.write("@RELATION AliensData\n");
        // Each row denotes the feature attribute
        // In this demo, the features have four dimensions.
        filewriter.write("@ATTRIBUTE gameScore  NUMERIC\n");
        filewriter.write("@ATTRIBUTE avatarSpeed  NUMERIC\n");
        filewriter.write("@ATTRIBUTE avatarHealthPoints NUMERIC\n");
        filewriter.write("@ATTRIBUTE avatarType NUMERIC\n");
        // objects
        for(int y=0; y<14; y++)
            for(int x=0; x<32; x++)
                filewriter.write("@ATTRIBUTE object_at_position_x=" + x + "_y=" + y + " NUMERIC\n");
        // The last row of the ARFF header stands for the classes
        filewriter.write("@ATTRIBUTE Class {0,1,2}\n");
        // The data will recorded in the following.
        filewriter.write("@Data\n");*/
        
    }
    
    public static Instance makeInstance(double[] features, int action, double reward){
        features[features.length-2] = action;
        features[features.length-1] = reward;
        Instance ins = new Instance(1, features);
        ins.setDataset(s_datasetHeader);
        return ins;
    }
    
    public static double[] featureExtract(StateObservation obs){
//----------------------------------------------------------------------------------- Original Implementation
//        double[] feature = new double[875];  // 868 + 4 + 1(action) + 1(Q)
//
//        // 448 locations
//        int[][] map = new int[28][31];
//        // Extract features
//        LinkedList<Observation> allobj = new LinkedList<>();
//        if( obs.getImmovablePositions()!=null )
//            for(ArrayList<Observation> l : obs.getImmovablePositions())
//                allobj.addAll(l);
//        if( obs.getMovablePositions()!=null )
//            for(ArrayList<Observation> l : obs.getMovablePositions())
//                allobj.addAll(l);
//
//        for(Observation o : allobj){
//            Vector2d p = o.position;
//            int x = (int)(p.x/28); //squre size is 28 for freeway?
//            int y= (int)(p.y/28);
//            map[x][y] = o.itype;
////            System.out.println(o.itype);
//        }
//        for(int y=0; y<31; y++) {
//            for (int x = 0; x < 28; x++) {
//                feature[y * 28 + x] = map[x][y];
//                System.out.print(map[x][y]);
//                System.out.print("  ");
//            }
//            System.out.println();
//        }
//        Vector2d aaa = obs.getAvatarPosition();
//        System.out.println(aaa.y/28);
//        System.out.println();
//
//        // 4 states
//        feature[868] = obs.getGameTick();
//        feature[869] = obs.getAvatarSpeed();
//        feature[870] = obs.getAvatarHealthPoints();
//        feature[871] = obs.getAvatarType();
//
//        //adjacent objects
//        Vector2d Avatar_pos = obs.getAvatarPosition();
//
//        return feature;
//-----------------------------------------------------------------------------------  My Implementation

        int[][] map = new int [28][31];
        LinkedList<Observation> allobj = new LinkedList<>();
        if (obs.getImmovablePositions()!=null) {
          for (ArrayList<Observation> l:obs.getImmovablePositions())
              allobj.addAll(l);
        }
        if (obs.getMovablePositions()!=null) {
            for (ArrayList<Observation> l:obs.getMovablePositions())
                allobj.addAll(l);
        }
        for (Observation o:allobj) {
            if (o.itype!=0){
            Vector2d p = o.position;
            int x = (int)(p.x/28);
            int y = (int)(p.x/28);
            map[x][y] = o.itype;}
        }

        Vector2d avatar_pos = obs.getAvatarPosition();
        int avatar_x = (int) avatar_pos.x/28;
        int avatar_y = (int) avatar_pos.y/28;

        HashMap<Integer, Vector2d> hashmap = new HashMap<>();
        hashmap.put(0, new Vector2d(avatar_x-1, avatar_y-1));
        hashmap.put(1, new Vector2d(avatar_x-1, avatar_y));
        hashmap.put(2, new Vector2d(avatar_x-1, avatar_y+1));
        hashmap.put(3, new Vector2d(avatar_x, avatar_y-1));
        hashmap.put(4, new Vector2d(avatar_x, avatar_y));
        hashmap.put(5, new Vector2d(avatar_x, avatar_y+1));
        hashmap.put(6, new Vector2d(avatar_x+1, avatar_y-1));
        hashmap.put(7, new Vector2d(avatar_x+1, avatar_y));
        hashmap.put(8, new Vector2d(avatar_x+1, avatar_y+1));

        double[] feature = new double[13];
        for (int index=0; index<feature.length; index++) feature[index] = 0;

        // detection for the walls and trucks
        for (int index=0; index<9; index++) {
            if (index==1||index==3||index==4||index==5||index==7) {
                Vector2d coordinates = hashmap.get(index);
                switch (map[(int) coordinates.x][(int) coordinates.y]) {
                    case 7:
                    case 8:
                    case 11:
                    case 10:
                        feature[index] += 40;
                        break;
                    case 13:
                        feature[index] += 5;
                        break;
                    default:
                        break;
                }
            }
        }

        // detection for the boundaries
        if (avatar_x==1) {
//            feature[0]+=5;
            feature[1]+=5;
//            feature[2]+=5;
        }
        else if (avatar_x==26) {
//            feature[6]+=5;
            feature[7]+=5;
//            feature[8]+=5;
        }

        if (avatar_y==1) {
//            feature[2]+=5;
            feature[5]+=5;
//            feature[8]+=5;
        }
        else if (avatar_y==13) {
//            feature[0]+=5;
            feature[3]+=5;
//            feature[6]+=5;
        }
        // other concerning features
        feature[9] = obs.getAvatarHealthPoints();
        feature[10] = obs.getGameTick();
        feature[11] = 0;
        feature[12] = 0;
        return feature;

    }
    
    public static Instances datasetHeader(){
        
//        if (s_datasetHeader!=null)
//            return s_datasetHeader;
//
//        FastVector attInfo = new FastVector();
//        // 448 locations
//        for(int y=0; y<28; y++){
//            for(int x=0; x<31; x++){
//                Attribute att = new Attribute("object_at_position_x=" + x + "_y=" + y);
//                attInfo.addElement(att);
//            }
//        }
//        Attribute att = new Attribute("GameTick" ); attInfo.addElement(att);
//        att = new Attribute("AvatarSpeed1" ); attInfo.addElement(att);
//        att = new Attribute("AvatarSpeed" ); attInfo.addElement(att);
//        att = new Attribute("AvatarHealthPoints" ); attInfo.addElement(att);
//        att = new Attribute("AvatarType" ); attInfo.addElement(att);
//        //action
//        FastVector actions = new FastVector();
//        actions.addElement("0");
//        actions.addElement("1");
//        actions.addElement("2");
//        actions.addElement("3");
//        att = new Attribute("actions", actions);
//        attInfo.addElement(att);
//        // Q value
//        att = new Attribute("Qvalue");
//        attInfo.addElement(att);
//
//        Instances instances = new Instances("PacmanQdata", attInfo, 0);
//        instances.setClassIndex( instances.numAttributes() - 1);
//
//        return instances;


        if (s_datasetHeader!=null)
            return s_datasetHeader;
        FastVector attInfo = new FastVector();
        // 9 locations
        Attribute att = new Attribute("LeftDown"); attInfo.addElement(att);
        att = new Attribute("LeftMiddle"); attInfo.addElement(att);
        att = new Attribute("LeftUp"); attInfo.addElement(att);
        att = new Attribute("MiddleDown"); attInfo.addElement(att);
        att = new Attribute("MiddleMiddle"); attInfo.addElement(att);
        att = new Attribute("MiddleUp"); attInfo.addElement(att);
        att = new Attribute("RightDown"); attInfo.addElement(att);
        att = new Attribute("RightMiddle"); attInfo.addElement(att);
        att = new Attribute("RightUp"); attInfo.addElement(att);
        att = new Attribute("HealthPoints"); attInfo.addElement(att);
        att = new Attribute("GameTick"); attInfo.addElement(att);

        //action
        FastVector actions = new FastVector();
        actions.addElement("0");
        actions.addElement("1");
        actions.addElement("2");
        actions.addElement("3");
        att = new Attribute("actions", actions);
        attInfo.addElement(att);

        // Q value
        att = new Attribute("QValue");
        attInfo.addElement(att);

        Instances instances = new Instances("FreeWayQData", attInfo, 0);

        instances.setClassIndex( instances.numAttributes() - 1);

        return instances;
    }
    
}
